#include "mainui.h"
#include "ui_mainui.h"
#include <QCryptographicHash>
#include <QObject>
#include <rsa.h>
#include <aes.h>
#include <QDir>
#include <QDebug>
#include <string.h>
#include <iostream>
#include <QPixmap>
#include <QPalette>
#include <QBitmap>
#include <QTime>
#include <QtCore/QObject>
#include <QTimer>
#include <aes_gcm.h>
mainui::mainui(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::mainui)
{
    ui->setupUi(this);
    //rsa_a.RSA_Initialize();
    rsa_a.e=2665;
    rsa_a.d=721945;
    rsa_a.n=3019123;
    server = new QTcpServer();
    QHostAddress address = QHostAddress(QHostAddress::LocalHost);
    QString strIPAddress = address.toString();
    ui->lineIP->setText(strIPAddress);
    ui->lineport->setText("5000");
    ui->sendmsg->setEnabled(false);
    connect(server,&QTcpServer::newConnection,this,&mainui::onNewConnection);//建立新连接时
//    /*
//     * set background image
//     */
//     QPixmap bgImages("://C:/Users/asus/Desktop/beijing1.jpg");
//     QPalette bgPalette = this->palette();
//     bgPalette.setBrush(QPalette::Background,bgImages);
//     this->setPalette(bgPalette);
//     setMask(bgImages.mask());// set background mask attribute same as background's image
     timer = new QTimer(this);
     connect(timer, SIGNAL(timeout()), this, SLOT(qtimeSlot()));
     timer->start(1000);
}
unsigned char* mainui::getkey(int k){//扩展为256位密钥
    unsigned char * r;
    r=new unsigned char[32];
    int i;
    for(i=0;i<32;i++){
        r[i]=(unsigned char)k;
    }
    return r;
}

void mainui::qtimeSlot()
{
    QTime qtimeObj = QTime::currentTime();
    QString strTime = qtimeObj.toString(" hh:mm:ss ");
    QDate qdateObj = QDate::currentDate();
    QString strDate = qdateObj.toString("yyyy-MM-dd");
    strDate+=strTime;
    ui->label->setText(strDate);
}

mainui::~mainui()
{
    delete ui;
}
void mainui::createdatabase()
{
    if (QSqlDatabase::contains("qt_sql_default_connection"))
    {
        database = QSqlDatabase::database("qt_sql_default_connection");
    }
    else
    {
        database = QSqlDatabase::addDatabase("QSQLITE");
        database.setDatabaseName("yonghu.db");
        database.setUserName("admin");
        database.setPassword("123456");
    }
}


void mainui::on_pushButton_clicked()//点击开始按钮
{
   server->disconnect();
   this->close();
   sendsignal_1();//发送退出信号
}
//客户端和服务器建立连接时，发送信号newConection
void mainui::onNewConnection(void)
{
ui->sendmsg->setEnabled(true);
QTcpSocket *client;
client=server->nextPendingConnection();
tcpClientList.append(client);
//当客户端给服务器发送消息时，发送信号readyRead
connect(client,SIGNAL(readyRead()),this,SLOT(slotDataReceived()));
connect(client, SIGNAL(disconnected()), this, SLOT(slotclientdisconnect()));
}

//接收客户端数据的槽函数
void mainui::slotDataReceived(void)
{
QString echo;//服务器返回的信息
//遍历所有客户端
    for(int i=0; i<tcpClientList.count(); i++)
    {
      //检查当前客户端套接子是否有数据到来
      if(tcpClientList.at(i)->bytesAvailable()){
          //读取消息
          QByteArray readbuf = QByteArray::fromBase64(tcpClientList.at(i)->readAll());
            //显示消息到服务器Ui,还未经处理，是乱码
            // ui->textEdit->append(QString::fromUtf8(readbuf));
          //进行数据分类操作
           QStringList list;
           userkeylist u;
           list=QString::fromUtf8(readbuf).split("-");//以"-"做分割
           if(list.at(0)=="request"){//如果是登录消息
                u.username=list.at(1);
                u.password=list.at(2);
                QString s;
                s=list.at(3);
                u.rsae=s.toInt();
                s=list.at(4);
                u.rsan=s.toInt();

                //DH g,p,KA
//                s=list.at(5);
//                DH.g=s.toInt();
//                s=list.at(6);
//                DH.p=s.toInt();
//                s=list.at(7);
//                DH.KA=s.toInt();
                s=list.at(5);
                int g=s.toInt();
                s=list.at(6);
                int p=s.toInt();

                if(g!=DH.g&&p!=DH.p){
                qDebug()<<"重新计算了～";
                s=list.at(5);
                DH.g=s.toInt();
                s=list.at(6);
                DH.p=s.toInt();
                s=list.at(7);
                DH.KA=s.toInt();
                DH.server_get_key();//服务器获取K，生成KB
                }
                qDebug()<<"--------------------";
                qDebug()<<"g:"<<DH.g;
                qDebug()<<"p:"<<DH.p;
                qDebug()<<"KA:"<<DH.KA;
                qDebug()<<"KB:"<<DH.KB;
                qDebug()<<"K:"<<DH.K;
                qDebug()<<"--------------------";


                //判断用户名和密码是否在数据库中，返回提示信息
                if (!database.open())
                {
                    qDebug() << "Error: Failed to connect database." << database.lastError();
                }
                else
                {
                    int valid=0;//判断用户名和密码是否在表中
                    int valid2=0;//判断用户是否已经登录
                    QString username,password,user0,pass0;
                    username=u.username;
                    password=u.password;
                    QSqlQuery query;
                    query.exec("select * from yonghu");
                    while( query.next()){//指向第一条记录
                    user0=query.value(1).toString();
                    pass0=query.value(2).toString();
                    if(!QString::compare(password,pass0)&&!QString::compare(username,user0)) //查到该用户,存在问题，如果两个账号同时登录的问题
                    {
                    valid=1;
                    }
                    }
                    for(int count=0;count<ulist.count();count++){//遍历用户列表
                        if(ulist.at(count).username==username){
                            valid2=1;
                        }
                    }
                    if(valid2){//如果用户已经登录了
                        QString msg="error-2-";//返回错误信息给当前客户端
                        tcpClientList.at(i)->write(msg.toUtf8().toBase64());
                        continue;
                    }
                    if(valid){//存在该用户且密码正确,返回 用户列表信息：ok-服务器rsa公钥e-n-KB-当前人数-用户名1-用户名2....
                        curruentusernum++;
                        u.aeskey=getkey(DH.K);
                        ulist.append(u);
                        int m=ulist.count();
                        qDebug()<<"m:"<<m;
                        ui->currentusernum->setText(QString::number(m));
                        echo="ok-"+QString::number(rsa_a.e)+"-"+QString::number(rsa_a.n)+"-"+QString::number(DH.KB)+"-"+QString::number(m)+"-";

                        int k;
                        for(k=0;k<ulist.count();k++){
                            echo+=ulist.at(k).username+"-";
                        }

                        QString s=echo;
                        int n=100;
                        int c=n-s.length();
                        int i;
                        s+="-";
                        for(i=0;i<c-1;i++){
                            s+="1";
                        }

                        qDebug()<<"echo "<<s;
                        for(int j=0;j<tcpClientList.count();j++){//转发给所有客户端
                             tcpClientList.at(j)->write(s.toUtf8().toBase64());
                        }
                        //显示用户列表
                        QStringList header;
                        header<<"当前用户人数";
                        ui->tableWidget->setColumnCount(1);
                        ui->tableWidget->setRowCount(0);
                        ui->tableWidget->setHorizontalHeaderLabels(header);//设置表头内容
                        QTableWidgetItem *Item;
                        ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
                        ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
                        ui->tableWidget->horizontalHeader()->setVisible(false); //隐藏行表头
                        ui->tableWidget->resizeColumnsToContents();
                        ui->tableWidget->resizeRowsToContents();
                        for(int i=0;i<ulist.count();i++){
                                    Item=new QTableWidgetItem(ulist.at(i).username);
                                    QFont font=Item->font();//获取原有字体设置
                                    font.setBold(true);//设置为粗体
                                    font.setPointSize(12);//字体大小
                                    Item->setTextColor(Qt::blue);//字体颜色
                                    Item->setFont(font);//设置字体
                                    int RowCont;
                                    RowCont=ui->tableWidget->rowCount();
                                    ui->tableWidget->insertRow(RowCont);//增加一行
                                    ui->tableWidget->setItem(i,0,Item);
                        }
                    }else{//没找到对应用户名和密码的记录，需要返回error
                        QString msg="error-1-";//返回错误信息给当前客户端
                        tcpClientList.at(i)->write(msg.toUtf8().toBase64());
                    }
                }
            }
            else if(list.at(0)=="data"){//接收到正常消息,显示到界面
               qDebug()<<"recv data from client";
               QString username;
               int length;
               username=list.at(1);
               QString s;
               s=list.at(2);
               length=s.toInt();
               qDebug()<<"username:"<<username;
               qDebug()<<"length:"<<length;
               int readbuflenth=readbuf.length();
               int i;
               //aes解密
               QString begin;//计算消息头的长度，AES密文的长度
               begin="data-"+username+"-"+list.at(2)+"-";
               QByteArray b=begin.toUtf8();
               qDebug()<<"b length"<<b.length();
               qDebug()<<"begin:"<<begin;
               qDebug()<<"begin length:"<<begin.length();
//               int beginlength=begin.length();
               int aescipherlength;
               aescipherlength=readbuf.length()-b.length();//aes密文长度
               QByteArray aescipherbytearray;/*
               for(i=beginlength;i<beginlength+aescipherlength;i++){//这里出现问题，这样不支持中文用户名，中文需要utf-8编码，求长度也要先转化为utf-8编码
                   aescipherbytearray.append(readbuf[i]);
               }*/
               for(i=b.length();i<b.length()+aescipherlength;i++){
                   aescipherbytearray.append(readbuf[i]);
               }
               qDebug()<<"readbuf length"<<readbuflenth;
               qDebug()<<"aescipherlength"<<aescipherbytearray.length();
               aes_gcm aesg(aesg.getgcmchar(getkey(DH.K),32));
               aesg.input2=aescipherbytearray;
               aesg.aes_decrypt();
               QString aesoutput;
               aesoutput=aesg.output2;
               qDebug()<<"aes output"<<aesoutput;

                //解密后的数据提取原文，进行MD5和签名验证
                QString msg;
                msg=aesoutput.mid(0,length);
                qDebug()<<"解密获得原文"<<msg;

                qDebug()<<"complete";
                QString uis;
                uis=username+":"+msg;
                ui->textEdit->append(uis);//转发消息给所有的客户端,服务器需要以自己的rsa私钥重新签名，以每个客户端的公钥加密
                sendmsg(msg,username);
           }
      }
    }
}
void mainui::on_start_clicked()//开始
{
    int port;
    port=ui->lineport->text().toInt();
    server->listen(QHostAddress::Any, port);
    ui->start->setEnabled(false);
}

void mainui::on_sendmsg_clicked()//发送消息到所有客户端
{
    QString echo="echo";//服务器发送的消息
    QString msg=ui->textEdit_2->toPlainText();
    ui->textEdit->append(echo+":"+msg);
    sendmsg(msg,echo);
}

void mainui::slotclientdisconnect(void){//客户端断开连接，服务器删除tcpclientlist，ulist相应位置,并发送离开消息和列表更新消息
    for(int i=0;i<tcpClientList.count();i++)
    {
        QTcpSocket *item=tcpClientList.at(i);
        if(item->socketDescriptor()==-1)
        {
            tcpClientList.removeAt(i);//如果有客户端断开连接， 就将列表中的套接字删除
            QString s;
            s="用户"+ulist.at(i).username+"退出了";
            QMessageBox::information(0,"infor",s);
            qDebug()<<"i:"<<i;
            qDebug()<<"ulist count:"<<ulist.count();
            QString msg;
            msg=ulist.at(i).username+"leave the chatroom";
            ulist.removeAt(i);
            //用户退出后，重新显示用户列表
            curruentusernum--;
            ui->currentusernum->setText(QString::number(curruentusernum));
            QStringList header;
            header<<"当前用户人数";
            ui->tableWidget->setColumnCount(1);
            ui->tableWidget->setRowCount(0);
            ui->tableWidget->setHorizontalHeaderLabels(header);//设置表头内容
            QTableWidgetItem *Item;
            ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
            ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
            ui->tableWidget->horizontalHeader()->setVisible(false); //隐藏行表头
            ui->tableWidget->resizeColumnsToContents();
            ui->tableWidget->resizeRowsToContents();
            qDebug()<<"helo 1";
            for(int j=0;j<ulist.count();j++){//更新用户列表
                        Item=new QTableWidgetItem(ulist.at(j).username);
                        QFont font=Item->font();//获取原有字体设置
                        font.setBold(true);//设置为粗体
                        font.setPointSize(12);//字体大小
                        Item->setTextColor(Qt::blue);//字体颜色
                        Item->setFont(font);//设置字体
                        int RowCont;
                        RowCont=ui->tableWidget->rowCount();
                        ui->tableWidget->insertRow(RowCont);//增加一行
                        ui->tableWidget->setItem(j,0,Item);
            }
            qDebug()<<"helo 2";
            sendmsg(msg,"echo");
                break;
        }
    }
    return;
}
QByteArray mainui::intTo4ByteArray(int i)
{
    QByteArray ba;
    ba.resize(4);
    ba[0] = (uchar)(0x000000ff & i);
    ba[1] = (uchar)((0x0000ff00&i)>>8);
    ba[2] = (uchar)((0x00ff0000&i)>>16);
    ba[3] = (uchar)((0xff000000&i)>>24);
    return ba;
}
int mainui::ByteArray4ToInt(const QByteArray &bytes)
{
    int i = bytes[0] & 0x000000FF;
    i |= ((bytes[1] <<8)&0x0000FF00);
    i |= ((bytes[2] <<16)&0x00FF0000);
    i |= ((bytes[3] <<24)&0xFF000000);
    return i;
}
void mainui::sendmsg(QString s,QString username)
{
    QString sendbuf = s;
    QString msg=sendbuf;
    int i;
    if(tcpClientList.count()==0){
        return;
    }
    for(int j=0;j<tcpClientList.count();j++){//RSA加密AES密钥的时候需要使用各个客户端自己的公钥
        //全过程要求ulist与当前的tcpClientList顺序一致
        rsa_b.e=ulist.at(j).rsae;
        rsa_b.n=ulist.at(j).rsan;
        aes_gcm aesg(aesg.getgcmchar(ulist.at(j).aeskey,32));
        //AES aes(key);//一次只能处理16字节数据，需要填充
        QString plaintext=msg;
        qDebug()<<"the length of plaintext for AES "<<plaintext.length();
        int l=plaintext.length();
        //先给输入字符串
        QString s=plaintext;
        int n=100;
        int c=n-s.length();
        int i;
        s+="-";
        for(i=0;i<c-1;i++){
            s+="1";
        }
        aesg.input1=s;
        aesg.aes_encrypt();//input1->output1,得到的密文是output1，一个QByteArray数组
        QByteArray rslt;
        rslt=aesg.output1;
        QString tmp;
        tmp="data-"+username+"-"+QString::number(msg.length())+"-";
        qDebug()<<"tmp :"<<tmp;
        int length;
        length=tmp.toUtf8().length();
        qDebug()<<"tmp length"<<length;
        rslt=tmp.toUtf8()+rslt;
        qDebug()<<"rslt length"<<rslt.length();
        tcpClientList.at(j)->write(rslt.toBase64());
        qDebug()<<"have send";
    }
}

void mainui::on_cleartextedit_clicked()
{
    ui->textEdit->clear();
}
